#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

#include <iostream>
#include <string>

using namespace std;

static void sigIntHandler(int sig) {
    return; // Just interrupt nanosleep
}

int main(int argc, char* argv[]) {
    if (argc != 3 || string(argv[1]) == "--help") {
        cout << argv[0] << " secs nanosecs" << endl;
        return 0;
    }

    struct timespec request;
    request.tv_sec  = stoi(argv[1]);
    request.tv_nsec = stoi(argv[1]);

    // Allow SIGINT handler to interrupt nanosleep()
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags   = 0;
    sa.sa_handler = sigIntHandler;
    if (sigaction(SIGINT, &sa, nullptr) == -1) {
        perror("sigaction");
        return 1;
    }

    struct timeval start;
    if (gettimeofday(&start, nullptr) == -1) {
        perror("gettimeofday");
        return 1;
    }

    struct timespec remain;
    struct timeval  finish;
    for (;;) {
        auto s = nanosleep(&request, &remain);
        if (s == -1 && errno != EINTR) {
            perror("nanosleep");
            return 1;
        }

        if (gettimeofday(&finish, nullptr) == -1) {
            perror("gettimeofday");
            return 1;
        }

        printf("Slept for: %9.6f secs\n",
               finish.tv_sec - start.tv_sec +
                   (finish.tv_usec - start.tv_usec) / 1000000.0);

        if (s == 0) {
            break; // nanosleep() completed
        }

        printf("Remaining: %2ld.%09ld\n", (long)remain.tv_sec,
               (long)remain.tv_nsec);
        request = remain; // Next sleep is with remaining time
    }

    cout << "Sleep complete" << endl;
    return 0;
}
